package main

import (
	"bufio"
	"context"
	"flag"
	"fmt"
	"goland-study/go_code/raft_demo/pkg/raft"
	"google.golang.org/grpc/codes"
	"google.golang.org/grpc/status"
	"log"
	"os"
	"strings"

	"google.golang.org/grpc"
)

func main() {
	serverAddr := flag.String("server", "localhost:50051", "Server address")
	flag.Parse()

	conn, err := grpc.Dial(*serverAddr, grpc.WithInsecure())
	if err != nil {
		log.Fatalf("Failed to connect: %v", err)
	}
	defer conn.Close()

	client := raft.NewRaftClient(conn)

	scanner := bufio.NewScanner(os.Stdin)
	fmt.Println("Raft CLI client. Type 'exit' to quit.")
	fmt.Print("raft> ")

	for scanner.Scan() {
		cmd := strings.TrimSpace(scanner.Text())
		if cmd == "exit" {
			break
		}

		if cmd == "" {
			fmt.Print("raft> ")
			continue
		}

		// 处理特殊命令
		if strings.HasPrefix(cmd, "add_server") {
			handleAddServer(client, cmd)
		} else if strings.HasPrefix(cmd, "remove_server") {
			handleRemoveServer(client, cmd)
		} else {
			// 普通命令
			resp, err := client.ExecuteCommand(context.Background(), &raft.CommandReq{
				Command: []byte(cmd),
			})

			if err != nil {
				if status, ok := status.FromError(err); ok {
					if status.Code() == codes.Unavailable {
						fmt.Println("Error: Leader unavailable")
					} else {
						fmt.Printf("RPC error: %v\n", status)
					}
				} else {
					fmt.Printf("Error: %v\n", err)
				}
			} else if resp.Success {
				fmt.Printf("Result: %s\n", string(resp.Result))
			} else {
				fmt.Printf("Redirect to leader: %d\n", resp.LeaderId)
				// 重新连接
				conn.Close()
				conn, _ = grpc.Dial(fmt.Sprintf("localhost:%d", 50050+resp.LeaderId), grpc.WithInsecure())
				client = raft.NewRaftClient(conn)
				fmt.Printf("Reconnected to new leader %d\n", resp.LeaderId)
			}
		}

		fmt.Print("raft> ")
	}
}

func handleAddServer(client raft.RaftClient, cmd string) {
	parts := strings.Fields(cmd)
	if len(parts) < 3 {
		fmt.Println("Usage: add_server <id> <address>")
		return
	}

	var id int
	var addr string
	fmt.Sscanf(parts[1], "%d", &id)
	addr = parts[2]

	_, err := client.AddServer(context.Background(), &raft.ServerReq{
		ServerId: int32(id),
		Address:  addr,
	})

	if err != nil {
		fmt.Printf("Error adding server: %v\n", err)
	} else {
		fmt.Println("Server add request submitted")
	}
}

func handleRemoveServer(client raft.RaftClient, cmd string) {
	parts := strings.Fields(cmd)
	if len(parts) < 2 {
		fmt.Println("Usage: remove_server <id>")
		return
	}

	var id int
	fmt.Sscanf(parts[1], "%d", &id)

	_, err := client.RemoveServer(context.Background(), &raft.ServerReq{
		ServerId: int32(id),
	})

	if err != nil {
		fmt.Printf("Error removing server: %v\n", err)
	} else {
		fmt.Println("Server remove request submitted")
	}
}
